/*
 * CUIprogramm.cpp
 *
 *  Created on: 2011-11-01
 *      Author: pawel
 */
#include<memory>
#include<exception>
#include"CUIprogramm.h"
#include<Bpp/Seq/Sequence.h>
#include"../seqFeederFile.h"
#include"../enumTypes.h"
#include"defaultParamValues.h"
#include"../algorithms.h"
#include"../alignContainerV.h"
#include"../optAlgs/needlemanWunsch.h"
#include"../optAlgs/smithWaterman.h"
#include"../heuristics/fastaAlg.h"
#include"../heuristics/fastaAlgParam.h"
#include"../scoreMatrix.h"
#include"../alignContainerF.h"
#include <boost/program_options.hpp>
#include"commandDesc.h"
#include"CUIEnums.h"
#include<iostream>
#include"../timer/Timer.h"
namespace po = boost::program_options;
CUIprogramm::CUIprogramm(int argc,char *argv[])
:optionsValid(false),message("")
{
	try{
		optAlgParam.alignContainerPtr	= NULL;
		optAlgParam.optAlgClassPtr		= NULL;
		optAlgParam.querySeqPtr			= NULL;
		optAlgParam.scoreMatrixPtr		= NULL;
		optAlgParam.seqFeederPtr		= NULL;

		std::string dbFileName;
		std::string queryFileName;
		std::string matrixFileName;
		std::string outFileName;
		po::options_description description(commandDesc::optionsDescriptionMessage);
		description.add_options()
		(commandDesc::helpOption.c_str(),commandDesc::helpMessage.c_str())
		(commandDesc::dbFileOption.c_str(),po::value<std::string>(&dbFileName),commandDesc::dbFileMessage.c_str())
		(commandDesc::queryFileOption.c_str(),po::value<std::string>(&queryFileName),commandDesc::queryFileMessage.c_str())
		(commandDesc::alphabetOption.c_str(),po::value<int>((int*)(&alphabet))->default_value((int)defaultParamValues::defaultAlphabet),commandDesc::alphabetMessage.c_str())
		(commandDesc::matrixOption.c_str(),po::value<std::string>(&matrixFileName),commandDesc::matrixMessage.c_str())
		(commandDesc::gopenOption.c_str(),po::value<int>(&optAlgParam.gopen)->default_value(defaultParamValues::defaultGopen),commandDesc::gopenMessage.c_str())
		(commandDesc::gextOption.c_str(),po::value<int>(&optAlgParam.gext)->default_value(defaultParamValues::defaultGext),commandDesc::gextMessage.c_str())
		(commandDesc::algorithmOption.c_str(),po::value<int>((int*)(&algorithm))->default_value((int)(defaultParamValues::defaultAlgorithm)),commandDesc::algorithmMessage.c_str())
		(commandDesc::kTupleOption.c_str(),po::value<size_t>(&fastaParam.k_tuple)->default_value(defaultParamValues::defaultKtuple),commandDesc::kTupleMessage.c_str())
		(commandDesc::wOption.c_str(),po::value<int>(&fastaParam.w)->default_value(defaultParamValues::defaultW),commandDesc::wMessage.c_str())
		(commandDesc::outFileOption.c_str(),po::value<std::string>(&outFileName),commandDesc::outFileMessage.c_str())
		(commandDesc::zScoreOption.c_str(),po::value<bool>(&zScore)->default_value(defaultParamValues::defaultZScore),commandDesc::zScoreMessage.c_str())

		(commandDesc::heurAlgThreadsOption.c_str(),po::value<size_t>(&heurAlgThreads)->default_value(defaultParamValues::defaultheurThread),commandDesc::heurAlgThreadsMessage.c_str())
(commandDesc::optAlgThreadsOption.c_str(),po::value<size_t>(&optAlgThreads)->default_value(defaultParamValues::defaultoptThread),commandDesc::optAlgThreadsMessage.c_str());

		;
        po::variables_map vm;
        po::store(po::parse_command_line(argc, argv, description), vm);
        po::notify(vm);
        optAlgParam.btrace = true;
        if(vm.count(commandDesc::helpOption.c_str())){
        	std::cout<<description<<std::endl;
        	//TODO object not initialised
        	optionsValid = false;
        	return;

        }
        std::auto_ptr<seqFeederFile> smartDbPtr(new seqFeederFile(dbFileName,alphabet));
        std::auto_ptr<seqFeederFile> smartQueryFeederPtr(new seqFeederFile(queryFileName,alphabet));
        std::auto_ptr<bpp::BasicSequence> smartQuerySeqPtr(smartQueryFeederPtr.get()->getSeq());
        std::auto_ptr<scoreMatrix> smartScoreMatrixPtr(new scoreMatrix(matrixFileName,alphabet));
        std::auto_ptr<alignContainerV> smartAlignContainer(new alignContainerF());
        outFile.open(outFileName.c_str(),std::ofstream::out);
        if(outFile.fail()){
        	throw std::ofstream::failure("Can not open: "+outFileName);
        }
        switch(algorithm){
        case NeWu:
        {
        	std::auto_ptr<optAlgClass> smartOptAlgPtr(new needlemanWunsch());
        	optAlgParam.optAlgClassPtr = smartOptAlgPtr.release();
        }
        break;
        case SmWm:
        {
        	std::auto_ptr<optAlgClass> smartOptAlgPtr(new smithWaterman());
        	optAlgParam.optAlgClassPtr = smartOptAlgPtr.release();
        }
        break;
        case Fast:
        {
        	std::auto_ptr<optAlgClass> smartOptAlgPtr(new smithWaterman());
        	optAlgParam.optAlgClassPtr = smartOptAlgPtr.release();
        }
        break;
        default:
        	throw std::logic_error("unknown algorithm");
        	break;
        }


        optAlgParam.seqFeederPtr = smartDbPtr.release();
        optAlgParam.querySeqPtr = smartQuerySeqPtr.release();
        optAlgParam.scoreMatrixPtr = smartScoreMatrixPtr.release();
        optAlgParam.alignContainerPtr = smartAlignContainer.release();
        queryFeeder =         smartQueryFeederPtr.release();

        optionsValid = true;
	}
	catch(std::exception &e){
		std::cerr<<e.what()<<std::endl;
		throw e;
	}
}
void CUIprogramm::runProgramm(){
	if(optionsValid){

		double time;
		Timer timer;
		timer.start();
		switch(algorithm){
			case NeWu:
			case SmWm:
			{
				optAlgThreadRunner(optAlgParam,optAlgThreads);
			}
			break;
			case Fast:
			{
				fastaAlg fastaAlgorithm(optAlgParam,optAlgThreads,heurAlgThreads,fastaParam);
				fastaAlgorithm.runAlg();
			}
			break;
		}
		timer.stop();
		time = timer.getElapsedTimeInSec();
		if(zScore){
			((alignContainerF*)(optAlgParam.alignContainerPtr))->calculateStats(10,optAlgParam,optAlgThreads);
			((alignContainerF*)(optAlgParam.alignContainerPtr))->sortByZScore();
		}
		else{
		((alignContainerF*)(optAlgParam.alignContainerPtr))->sortByScore();
		}
		outFile<<(*(alignContainerF*)(optAlgParam.alignContainerPtr));
		std::cout<<"Eplased Time:\t"<<time<<"[s]"<<std::endl;
	}
	else{
		throw std::logic_error("Bad option");
	}
}
CUIprogramm::~CUIprogramm(){

	if(optAlgParam.alignContainerPtr != NULL)delete optAlgParam.alignContainerPtr;
	if(optAlgParam.optAlgClassPtr != NULL)delete optAlgParam.optAlgClassPtr;
	if(optAlgParam.querySeqPtr != NULL)delete optAlgParam.querySeqPtr;
	if(optAlgParam.scoreMatrixPtr != NULL)delete optAlgParam.scoreMatrixPtr;
	if(optAlgParam.seqFeederPtr != NULL)delete optAlgParam.seqFeederPtr;
	if(queryFeeder != NULL)delete queryFeeder;
	outFile.close();

}

